package com.sai.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sai.common.api.vo.Result;
import com.sai.common.constant.CacheConstant;
import com.sai.common.constant.CommonConstant;
import com.sai.common.exception.CommonServiceException;
import com.sai.common.system.api.ISysBaseAPI;
import com.sai.common.system.query.QueryGenerator;
import com.sai.common.system.util.JwtUtil;
import com.sai.common.system.vo.LoginUser;
import com.sai.common.system.vo.SysUserCacheInfo;
import com.sai.common.utils.ConvertUtils;
import com.sai.common.utils.PasswordUtil;
import com.sai.system.entity.*;
import com.sai.system.mapper.*;
import com.sai.system.service.ISysUserService;
import com.sai.system.vo.SysUserDepVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户表 服务实现类
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

	@Autowired
	private SysPermissionMapper sysPermissionMapper;
	@Autowired
	private SysUserRoleMapper sysUserRoleMapper;
	@Autowired
	private SysUserMapper userMapper;
	@Autowired
	private SysUserDepartMapper sysUserDepartMapper;
	@Autowired
	private ISysBaseAPI sysBaseAPI;
	@Autowired
	private SysDepartMapper sysDepartMapper;

	/**
	 * 查询登录用户信息
	 * @param
	 * @return
	 */
	public SysUser getCurrentUserInfo() {
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		return getUserByName(sysUser.getUsername());
	}

	/**
	 * 查询登录用户关联的部门
	 * @param
	 * @return
	 */
	public List<SysDepart> getCurrentUserDeparts() {
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		return sysDepartMapper.queryUserDeparts(sysUser.getId());
	}

	/**
	 * 登录用户部门切换
	 * @param orgCode
	 * @return
	 */
	public SysUser updateCurrentUserDepart(String orgCode) {
		if (StrUtil.isEmpty(orgCode)) {
			throw new CommonServiceException("部门编码不能为空");
		}
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		List<SysDepart> sysDeparts = sysDepartMapper.queryUserDeparts(sysUser.getId());
		long num = sysDeparts.stream().filter(depart -> orgCode.equals(depart.getOrgCode())).count();
		if (num == 0) {
			throw new CommonServiceException("无效的部门编码");
		}
		this.updateUserDepart(sysUser.getUsername(), orgCode);
		return getUserByName(sysUser.getUsername());
	}

	/**
	 * 分页查询用户列表
	 * @param user
	 * @param pageNo
	 * @param pageSize
	 * @param parameterMap
	 * @return
	 */
	public IPage<SysUser> pageUser(SysUser user, Integer pageNo, Integer pageSize, Map<String, String[]> parameterMap) {
		QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(user, parameterMap);
		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
		IPage<SysUser> pageList = this.page(page, queryWrapper);

		//批量查询用户的所属部门
		//step.1 先拿到全部的 useids
		//step.2 通过 useids，一次性查询用户的所属部门名字
		List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList());
		if(userIds!=null && userIds.size()>0){
			Map<String,String> useDepNames = this.getDepNamesByUserIds(userIds);
			pageList.getRecords().forEach(item->{
				//TODO 临时借用这个字段用于页面展示
				item.setOrgCode(useDepNames.get(item.getId()));
			});
		}
		return pageList;
	}

	/**
	 * 查询用户列表
	 * @param user
	 * @param parameterMap
	 * @return
	 */
	public List<SysUser> list(SysUser user, Map<String, String[]> parameterMap) {
		QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(user, parameterMap);
		return this.list(queryWrapper);
	}

	/**
	 * 新增系统用户
	 * @param user
	 * @param selectedRoles
	 * @param selectedDeparts
	 * @return
	 */
	public SysUser addUser(SysUser user, String selectedRoles, String selectedDeparts) {
		String salt = ConvertUtils.randomGen(8);
		user.setSalt(salt);
		String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
		user.setPassword(passwordEncode);
		user.setStatus(1);
		user.setDelFlag("0");
		this.save(user);
		this.addUserWithRole(user, selectedRoles);
		this.addUserWithDepart(user, selectedDeparts);
		return user;
	}

	/**
	 * 修改系统用户
	 * @param user
	 * @param selectedRoles
	 * @param selectedDeparts
	 * @return
	 */
	public SysUser editUser(SysUser user, String selectedRoles, String selectedDeparts) {
		SysUser sysUser = this.getById(user.getId());
		if (sysUser == null) {
			throw new CommonServiceException("用户不存在");
		}
		user.setPassword(sysUser.getPassword());
		this.updateById(user);
		this.editUserWithRole(user, selectedRoles);
		this.editUserWithDepart(user, selectedDeparts);
		return user;
	}

	@Override
	@Transactional
	@CacheEvict(value={CacheConstant.SYS_USERS_CACHE}, allEntries=true)
	public void editUserWithDepart(SysUser user, String departs) {
		//先删后加
		sysUserDepartMapper.delete(new QueryWrapper<SysUserDepart>().lambda().eq(SysUserDepart::getUserId, user.getId()));
		if(StrUtil.isNotEmpty(departs)) {
			String[] arr = departs.split(",");
			for (String departId : arr) {
				SysUserDepart userDepart = new SysUserDepart(user.getId(), departId);
				sysUserDepartMapper.insert(userDepart);
			}
		}
	}

	@Override
	@CacheEvict(value= {CacheConstant.SYS_USERS_CACHE}, allEntries=true)
	@Transactional
	public void editUserWithRole(SysUser user, String roles) {
		//先删后加
		sysUserRoleMapper.delete(new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getUserId, user.getId()));
		if(StrUtil.isNotEmpty(roles)) {
			String[] arr = roles.split(",");
			for (String roleId : arr) {
				SysUserRole userRole = new SysUserRole(user.getId(), roleId);
				sysUserRoleMapper.insert(userRole);
			}
		}
	}

	@CacheEvict(value= {CacheConstant.SYS_USERS_CACHE}, key="#username")
	public void updateUserDepart(String username,String orgCode) {
		baseMapper.updateUserDepart(username, orgCode);
	}

	/**
	 * 通过用户名获取用户角色集合
	 * @param username 用户名
	 * @return 角色集合
	 */
	@Override
	public Set<String> getUserRolesSet(String username) {
		// 查询用户拥有的角色集合
		List<String> roles = sysUserRoleMapper.getRoleByUserName(username);
		log.info("-------通过数据库读取用户拥有的角色Rules------username： " + username + ",Roles size: " + (roles == null ? 0 : roles.size()));
		return new HashSet<>(roles);
	}

	/**
	 * 通过用户名获取用户权限集合
	 *
	 * @param username 用户名
	 * @return 权限集合
	 */
	@Override
	public Set<String> getUserPermissionsSet(String username) {
		Set<String> permissionSet = new HashSet<>();
		List<SysPermission> permissionList = sysPermissionMapper.queryByUser(username);
		for (SysPermission po : permissionList) {
			if (StrUtil.isNotEmpty(po.getPerms())) {
				permissionSet.add(po.getPerms());
			}
		}
		log.info("-------通过数据库读取用户拥有的权限Perms------username： "+ username+",Perms size: "+ (permissionSet==null?0:permissionSet.size()) );
		return permissionSet;
	}

	@Override
	public SysUser getUserByName(String username) {
		return userMapper.getUserByName(username);
	}

	/**
	 * 校验用户是否有效
	 * @param sysUser
	 * @return
	 */
	@Override
	public Result<?> checkUserIsEffective(SysUser sysUser) {
		//情况1：根据用户信息查询，该用户不存在
		if (sysUser == null) {
//			sysBaseAPI.addLog("用户登录失败，用户不存在！", CommonConstant.LOG_TYPE_1, null);
			return Result.error500("该用户不存在，请注册");
		}
		//情况2：根据用户信息查询，该用户已注销
		if (CommonConstant.DEL_FLAG_1.toString().equals(sysUser.getDelFlag())) {
//			sysBaseAPI.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已注销！", CommonConstant.LOG_TYPE_1, null);
			return Result.error500("该用户已注销");
		}
		//情况3：根据用户信息查询，该用户已冻结
		if (CommonConstant.USER_FREEZE.equals(sysUser.getStatus())) {
//			sysBaseAPI.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已冻结！", CommonConstant.LOG_TYPE_1, null);
			return Result.error500("该用户已冻结");
		}
		return Result.ok();
	}

	@Override
	public Map<String, String> getDepNamesByUserIds(List<String> userIds) {
		List<SysUserDepVo> list = this.baseMapper.getDepNamesByUserIds(userIds);

		Map<String, String> res = new HashMap<String, String>();
		list.forEach(item -> {
					if (res.get(item.getUserId()) == null) {
						res.put(item.getUserId(), item.getDepartName());
					} else {
						res.put(item.getUserId(), res.get(item.getUserId()) + "," + item.getDepartName());
					}
				}
		);
		return res;
	}

	@Override
	@Transactional
	public void addUserWithRole(SysUser user, String roles) {
		if(StrUtil.isNotEmpty(roles)) {
			String[] arr = roles.split(",");
			for (String roleId : arr) {
				SysUserRole userRole = new SysUserRole(user.getId(), roleId);
				sysUserRoleMapper.insert(userRole);
			}
		}
	}

	@Override
	@Transactional
	public void addUserWithDepart(SysUser user, String selectedParts) {
		if(StrUtil.isNotEmpty(selectedParts)) {
			String[] arr = selectedParts.split(",");
			for (String deaprtId : arr) {
				SysUserDepart userDeaprt = new SysUserDepart(user.getId(), deaprtId);
				sysUserDepartMapper.insert(userDeaprt);
			}
		}
	}

	@Override
	public SysUserCacheInfo getCacheUser(String username) {
		SysUserCacheInfo info = new SysUserCacheInfo();
		info.setOneDepart(true);
//		SysUser user = userMapper.getUserByName(username);
//		info.setSysUserCode(user.getUsername());
//		info.setSysUserName(user.getRealname());


		LoginUser user = sysBaseAPI.getUserByName(username);
		if(user!=null) {
			info.setSysUserCode(user.getUsername());
			info.setSysUserName(user.getRealname());
			info.setSysOrgCode(user.getOrgCode());
		}

		//多部门支持in查询
		List<SysDepart> list = sysDepartMapper.queryUserDeparts(user.getId());
		List<String> sysMultiOrgCode = new ArrayList<String>();
		if(list==null || list.size()==0) {
			//当前用户无部门
			//sysMultiOrgCode.add("0");
		}else if(list.size()==1) {
			sysMultiOrgCode.add(list.get(0).getOrgCode());
		}else {
			info.setOneDepart(false);
			for (SysDepart dpt : list) {
				sysMultiOrgCode.add(dpt.getOrgCode());
			}
		}
		info.setSysMultiOrgCode(sysMultiOrgCode);

		return info;
	}

}
